package XunChunCPU.ID

import chisel3._
import chisel3.util._
import XunChunCPU.common.Bundles._
import XunChunCPU.common.CommonConfig._

class Decode extends Module {
    val io = IO(new Bundle{
        val instr_in = Input(UInt(instrLen.W))
        val pc_in = Input(UInt(instrAddrLen.W))
        val controlInfo = new ControlInfo               //
        val instr_out = Output(UInt(instrLen.W))        //
        val pc_out = Output(UInt(instrAddrLen.W))       //
        val ready_out = Output(Bool())
        val ready_in = Input(Bool())
    })

    io.instr_out := io.instr_in
    io.pc_out := io.pc_in

    // controlInfo
    val controlSignals : List[UInt] = ListLookup(io.instr_in,
                           List(InstrN, wDisable,   wAddr_0,    FromRS, FromRT, ZeroExt,    OP_NOP),
        Array(
            // 算术指令
            ADD         -> List(InstrY, wEnable,    wAddr_rd,   FromRS, FromRT, SignExt,    OP_ADD),
            ADDI        -> List(InstrY, wEnable,    wAddr_rt,   FromRS, FromImm,SignExt,    OP_ADD),
            ADDU        -> List(InstrY, wEnable,    wAddr_rd,   FromRS, FromRT, ZeroExt,    OP_ADDU),
            ADDIU       -> List(InstrY, wEnable,    wAddr_rt,   FromRS, FromImm,SignExt,    OP_ADDU),
            SUB         -> List(InstrY, wEnable,    wAddr_rd,   FromRS, FromRT, ZeroExt,    OP_SUB),
            SLT         -> List(InstrY, wEnable,    wAddr_rd,   FromRS, FromRT, ZeroExt,    OP_SLT),
            MUL         -> List(InstrY, wEnable,    wAddr_rd,   FromRS, FromRT, ZeroExt,    OP_MUL),
            // 逻辑指令
            AND         -> List(InstrY, wEnable,    wAddr_rd,   FromRS, FromRT, ZeroExt,    OP_AND),
            ANDI        -> List(InstrY, wEnable,    wAddr_rt,   FromRS, FromImm,ZeroExt,    OP_AND),
            LUI         -> List(InstrY, wEnable,    wAddr_rt,   FromRS, FromImm,ZeroExt,    OP_LUI),
            OR          -> List(InstrY, wEnable,    wAddr_rd,   FromRS, FromRT, ZeroExt,    OP_OR),
            ORI         -> List(InstrY, wEnable,    wAddr_rt,   FromRS, FromImm,ZeroExt,    OP_OR),
            XOR         -> List(InstrY, wEnable,    wAddr_rd,   FromRS, FromRT, ZeroExt,    OP_XOR),
            XORI        -> List(InstrY, wEnable,    wAddr_rt,   FromRS, FromImm,ZeroExt,    OP_XOR),
            // 移位指令
            SLLV        -> List(InstrY, wEnable,    wAddr_rd,   FromRS, FromRT, ZeroExt,    OP_SLL),
            SLL         -> List(InstrY, wEnable,    wAddr_rd,   FromSA, FromRT, ZeroExt,    OP_SLL),
            SRAV        -> List(InstrY, wEnable,    wAddr_rd,   FromRS, FromRT, ZeroExt,    OP_SRA),
            SRA         -> List(InstrY, wEnable,    wAddr_rd,   FromSA, FromRT, ZeroExt,    OP_SRA),
            SRLV        -> List(InstrY, wEnable,    wAddr_rd,   FromRS, FromRT, ZeroExt,    OP_SRL),
            SRL         -> List(InstrY, wEnable,    wAddr_rd,   FromSA, FromRT, ZeroExt,    OP_SRL),
            // 分支跳转指令
            BEQ         -> List(InstrY, wDisable,   wAddr_0,    FromRS, FromRT, ZeroExt,    OP_BEQ),
            BNE         -> List(InstrY, wDisable,   wAddr_0,    FromRS, FromRT, ZeroExt,    OP_BNE),
            BGEZ        -> List(InstrY, wDisable,   wAddr_0,    FromRS, FromRT, ZeroExt,    OP_BGEZ),
            BGTZ        -> List(InstrY, wDisable,   wAddr_0,    FromRS, FromRT, ZeroExt,    OP_BGTZ),
            BLEZ        -> List(InstrY, wDisable,   wAddr_0,    FromRS, FromRT, ZeroExt,    OP_BLEZ),
            BLTZ        -> List(InstrY, wDisable,   wAddr_0,    FromRS, FromRT, ZeroExt,    OP_BLTZ),
            J           -> List(InstrY, wDisable,   wAddr_0,    FromRS, FromRT, ZeroExt,    OP_J),
            JAL         -> List(InstrY, wEnable,    wAddr_31,   FromAddrImm,FromZero, ZeroExt,    OP_JAL),
            JR          -> List(InstrY, wDisable,   wAddr_0,   FromRS, FromZero,   ZeroExt,    OP_JR),
            JALR        -> List(InstrY, wEnable,    wAddr_rd,   FromAddrImm, FromZero,   ZeroExt,    OP_JALR),
            LB          -> List(InstrY, wEnable,    wAddr_rt,   FromOffset, FromRT, ZeroExt,   OP_LB),
            LW          -> List(InstrY, wEnable,    wAddr_rt,   FromOffset, FromRT, ZeroExt,   OP_LW),
            SB          -> List(InstrY, wDisable,   wAddr_0,    FromOffset, FromRT, ZeroExt,    OP_SB),
            SW          -> List(InstrY, wDisable,   wAddr_0,    FromOffset, FromRT, ZeroExt,    OP_SW)
        )
    )

    io.controlInfo.InstrValid := controlSignals(0)
    io.controlInfo.regwe := controlSignals(1)
    io.controlInfo.wAddrSel := controlSignals(2)
    io.controlInfo.ASel := controlSignals(3)
    io.controlInfo.BSel := controlSignals(4)
    io.controlInfo.immExtType := controlSignals(5)
    io.controlInfo.op := controlSignals(6)

    // ready-valid
    // 如果控制单元ready了，译码就ready了
    io.ready_out := io.ready_in

}